#include "FPCH.h"

#include "FFaceHandle.h"

#include "FGlyph.h"
#include "FGlyphPage.h"
#include "FGlyphMap.h"
#include "FText.h"
#include "FCharMap.h"
#include "FMetrics.h"
#include "FKerningTable.h"
#include "FTextInstructionsUtf16.h"

namespace Font
{

	FaceHandle::FaceHandle(Library* a_Library, Family* a_Owner)
	{
		m_Library = a_Library;

		m_Owner = a_Owner;

		m_GlyphFilled = m_GlyphTotal = 0;
		m_Glyph = NULL;

		m_Texture = NULL;
		m_GlyphMap = NULL;
		m_Kerning = NULL;

		m_Paging = true;
		m_PagingMinimumLevel = 8;
	}

	FaceHandle::~FaceHandle()
	{
		if (m_Glyph) { delete [] m_Glyph; }
		if (m_Texture) { delete m_Texture; }
		if (m_GlyphMap) { delete m_GlyphMap; }
	}

	void FaceHandle::SetMetrics(Metrics* a_Metrics)
	{
		m_Metrics = a_Metrics;
	}

	void FaceHandle::SetFontSize(unsigned int a_FontSize, unsigned int a_LineHeight)
	{
		m_Size = a_FontSize;
		m_SizeReal = a_LineHeight;
	}

	GlyphMap* FaceHandle::GetGlyphMap()
	{
		if (!m_GlyphMap)
		{
			std::vector<Glyph*> glyphs;

			const std::vector<UnicodeRange*>& ranges = m_Map->GetUnicodeRanges();
			for (size_t j = 0; j < ranges.size(); j++)
			{
				UnicodeRange* curr = ranges[j];

				for (unsigned int i = curr->start; i < curr->end; i++)
				{
					if (!m_Glyph[i]->CheckValid()) { continue; }

					glyphs.push_back(m_Glyph[i]);
				}
			}
			
			m_GlyphMap = new GlyphMap(m_Library, this);
			m_GlyphMap->PackGlyphs(glyphs, m_PagingMinimumLevel, m_Paging);
			m_GlyphMap->SetDefault(m_Map->GetDefault());
		}

		return m_GlyphMap;
	}

	tb::Pos2 FaceHandle::GetMessageDimensions(const tb::StringBase<wchar_t>& a_Message)
	{
		/*unsigned int w = 0;
		unsigned int h = (unsigned int)m_SizeReal;
		int y_min = 1000;
		int y_max = 0;
		Glyph* prev = NULL;

		for (int i = 0; i < a_Message.GetLength(); i++)
		{
			Glyph* curr = GetGlyph(a_Message[i]);
			if (!curr) { continue; }

			w += curr->GetBearing().x;
			w += curr->GetAdvance().x;
			if (prev) { w += prev->GetKerning(curr); }

			y_min = (curr->GetBearing().y < y_min) ? curr->GetBearing().y : y_min;
			y_max = (curr->GetPosYMax() > y_max) ? curr->GetPosYMax() : y_max;

			prev = curr;
		}

		return tb::Pos2(
			w, 
			y_max - y_min
		);*/

		return tb::Pos2(0, 0);
	}

	Text* FaceHandle::CreateText(const wchar_t* a_Message)
	{
		const unsigned char* src_string = (const unsigned char*)a_Message;
		unsigned int src_length = wcslen(a_Message);

		if (src_length == 0) { return NULL; }

		GetGlyphMap();

		Text* result = new Text(m_Library, this);
		result->SetInstructions(new TextInstructionsUtf16(m_Library));
		if (!result->Write(src_string, src_length))
		{
			delete result;
			return NULL;
		}

		return result;
	}

	Text* FaceHandle::CreateText(TextInstructions* a_Instructions)
	{
		GetGlyphMap();

		Text* result = new Text(m_Library, this);
		result->SetInstructions(a_Instructions);
		if (!result->WriteInstructions())
		{
			delete result;
			return NULL;
		}

		return result;
	}

	Glyph* FaceHandle::GetGlyph(wchar_t a_Character)
	{
		if (a_Character >= m_GlyphTotal) { return NULL; }
		Glyph* result = m_Glyph[a_Character];
		if (!result->CheckValid()) 
		{ 
			return m_GlyphDefault; 
		}
		return result;
	}

	Glyph* FaceHandle::GetNextGlyph(unsigned int a_Index)
	{
		m_GlyphFilled++;
		return m_Glyph[a_Index];
	}

	Glyph* FaceHandle::GetNextGlyph()
	{
		return m_Glyph[m_GlyphFilled++];
	}

	void FaceHandle::SetGlyphTotal(unsigned int a_Count)
	{
		m_GlyphTotal = a_Count;
		m_GlyphFilled = 0;
		m_Glyph = new Glyph*[m_GlyphTotal];
		for (unsigned int i = 0; i < m_GlyphTotal; i++)
		{
			m_Glyph[i] = new Glyph(m_Library);
		}
	}

	void FaceHandle::SetGlyphRange(unsigned int a_RangeStart, unsigned int a_RangeEnd)
	{
		m_GlyphTotal = a_RangeStart + (a_RangeEnd - a_RangeStart);
		m_GlyphFilled = 0;
		m_Glyph = new Glyph*[m_GlyphTotal];
		for (unsigned int i = 0; i < m_GlyphTotal; i++)
		{
			m_Glyph[i] = new Glyph(m_Library);
		}
	}

	void FaceHandle::SetKerningTable(KerningTable* a_Table)
	{
		m_Kerning = a_Table;
	}

	void FaceHandle::SetCharMap(CharMap* a_Map)
	{
		m_Map = a_Map;
	}

	unsigned int FaceHandle::GetHeightNewLine()
	{
		//return GetTexture()->GetDistanceNewLine();
		return m_SizeReal;
	}

	KerningTable* FaceHandle::GetKerningTable()
	{
		return m_Kerning;
	}

	int FaceHandle::GetKerning(wchar_t a_Left, wchar_t a_Right)
	{
		if (!m_Kerning) { return 0; }

		return m_Kerning->GetKerning(a_Left, a_Right);
	}

	void FaceHandle::SetPaging(bool a_State, unsigned int a_MinimumLevel)
	{
		m_Paging = a_State;
		m_PagingMinimumLevel = a_MinimumLevel;
	}

	Family* FaceHandle::GetFamily()
	{
		return m_Owner;
	}

}; // namespace Font